シェーダー内でDDX、DDYメソッドを見たことがありますがピンと来てなかったところ 過去のUnity道場の資料を見て雰囲気をつかめたので処理を抜粋
// こんな感じの
ddx(i.uv)
ddy(i.uv)
https://www.slideshare.net/UnityTechnologiesJapan/unity-2-133372753
「DDX、DDYメソッドは隣接するピクセル情報との差分を求める」 しかしフラグメントシェーダーは並列して処理しているため、他のピクセル情報を取得できるのか。 というのは疑問点でありましたが、上記資料ではフラグメントシェーダーは2x2の4ピクセル同時に処理されているようでした
つまり、同時に実行されていることからDDX、DDYでは隣接するピクセルの情報との差分が取得できるということのようです メモリもローカルに乗ったままなので処理速度も遅くないとのこと
fwidthメソッドが隣接するX、Yのピクセル差分を絶対値で足し合わせているメソッドのようで
fwidth(v) = abs(ddx(v)) + abs(ddy(v))
こちらにColor値を入れてそれを返していました。 その結果がみぎのような輪郭が黒く表示されるシェーダーとなるとのこと。
つまり隣接するピクセルの差分同士を足し合わせてそれをフラグメントシェーダーの結果として返しています。 自分が不透明なピクセルであるとき、隣接するピクセルのColorアルファ値が同じく不透明であると 1 - 1 = 0(差分) でアルファ値が0となり透明化。
しかし、隣接が透明(α値0)との差分の場合 1 - 0 = 1 と、結果としてアルファ値が1で出力されます
なので上記の場合、アルファの差分が出る輪郭のみが表示されるようです
前回のURPシェーダーに手を加えた結果が以下
Shader "Custom/DDX_DDY"
{
Properties
{
_MainTex ("Main Tex", 2D) = "while" {}
}
SubShader
{
Tags
{
"RenderType" = "Transparent"
"RenderPipeline" = "UniversalPipeline"
"IgnoreProjector" = "True"
"Queue" = "Transparent"
}
Blend SrcAlpha OneMinusSrcAlpha
Pass
{
HLSLPROGRAM
#pragma vertex vert
#pragma fragment flag
// HLSLのマクロやメソッドの定義
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl"
struct Attributes
{
float4 positionOS : POSITION;
float2 uv : TEXCOORD0; // テクスチャ座標
};
struct Varyings
{
float4 positionHCS : SV_POSITION;
float2 uv : TEXCOORD0; // テクスチャ座標
};
sampler2D _MainTex;
// 頂点の出力
Varyings vert(Attributes IN)
{
Varyings o;
o.positionHCS = TransformObjectToHClip(IN.positionOS.xyz);
o.uv = IN.uv;
return o;
}
half4 flag(Varyings IN) : SV_Target
{
// 保管されたUV座標でテクスチャから色を得る
half4 col = tex2D(_MainTex, IN.uv);
return fwidth(col);
}
ENDHLSL
}
}
}
もう少し手を加えて、fwidthをそのまま帰すのではなくlerpで差分が出るとき(輪郭)のみ黒が描画されるようにした場合
return lerp(col, fixed4(0, 0, 0, 1), fwidth(col.a));
画像の輪郭が描画されるようになりました。(腕や髪がわかりやすい
ddx, ddyの特性をつかむことができました